#include "PriorizadorMaterias.h"

using namespace modelo;

PriorizadorMaterias::PriorizadorMaterias(ContextoDeEjecucion* otroContexto)
{
	this->contexto = otroContexto;
	this->matrizAdyacencia = new MatrizAdyacencia(this->contexto->GetInformacionMaterias());
};

list<MateriaPriorizada*> PriorizadorMaterias::PriorizarMaterias()
{
	this->ArmarArbolCorrelatividades();
	list<MateriaPriorizada*> materiasPriorizadas = this->CalcularPrioridadesMaterias();
	this->CalcularRequisitosParaCadaMateria(&materiasPriorizadas);
	this->CalcularMateriasPosterioresParaCadaMateria(&materiasPriorizadas);
	return materiasPriorizadas;
};

void PriorizadorMaterias::CalcularRequisitosParaCadaMateria(list<MateriaPriorizada*>* materiasPriorizadasPt)
{
	list<MateriaPriorizada*> materiasPriorizadas = *materiasPriorizadasPt;
	list<MateriaPriorizada*>::iterator itMatPriorizada;
	for(itMatPriorizada = materiasPriorizadas.begin(); itMatPriorizada != materiasPriorizadas.end(); itMatPriorizada++)
	{
		this->matrizAdyacencia->CalcularRequisitosParaCursar((*itMatPriorizada)->GetInformacionMateriaSegunCarrera());
	}
};

void PriorizadorMaterias::CalcularMateriasPosterioresParaCadaMateria(list<MateriaPriorizada*>* materiasPriorizadasPt)
{
	list<MateriaPriorizada*> materiasPriorizadas = *materiasPriorizadasPt;
	list<MateriaPriorizada*>::iterator itMatPriorizada;
	for(itMatPriorizada = materiasPriorizadas.begin(); itMatPriorizada != materiasPriorizadas.end(); itMatPriorizada++)
	{
		this->matrizAdyacencia->CalcularMateriasPosterioresPara((*itMatPriorizada)->GetInformacionMateriaSegunCarrera());
	}
};

list<MateriaPriorizada*> PriorizadorMaterias::CalcularPrioridadesMaterias() 
{
	list<MateriaPriorizada*> materiasPriorizadas;
	list<InformacionMateria*> informacionMaterias = this->contexto->GetInformacionMaterias();
	list<InformacionMateria*>::iterator itInformacionMaterias;
	for(itInformacionMaterias = informacionMaterias.begin(); 
		itInformacionMaterias !=  informacionMaterias.end(); itInformacionMaterias++)
	{
		InformacionMateriaSegunCarrera* informacionMateriaSegunCarrera = 
			this->contexto->BuscarInformacionMateriaSegunCarrera((*itInformacionMaterias)->GetCodigo());
		if(informacionMateriaSegunCarrera == NULL)
		{
			continue;//Esto ocurre cuando se busca una materia que no figura entre las optativas ni las obligatorias.
		}
		MateriaPriorizada* materiaPriorizada = new MateriaPriorizada(*itInformacionMaterias, informacionMateriaSegunCarrera);
		int prioridad = this->matrizAdyacencia->SumarCorrelativasPara(materiaPriorizada->GetInformacionMateria()->GetCodigo());
		materiaPriorizada->IncrementarPrioridad(prioridad);
		materiasPriorizadas.push_back(materiaPriorizada);
	}
	return materiasPriorizadas;
};


void PriorizadorMaterias::ArmarArbolCorrelatividades()
{
	list<InformacionMateria*> informacionMaterias = this->contexto->GetInformacionMaterias();
	list<InformacionMateria*>::iterator itMaterias;
	for(itMaterias = informacionMaterias.begin(); itMaterias != informacionMaterias.end(); itMaterias++)
	{
		InformacionMateria* informacionMateria = * itMaterias;
		this->ArmarArbolCorrelatividadesPara(informacionMateria->GetCodigo());
	}
};

void PriorizadorMaterias::ArmarArbolDeCorrelatividadesDePrimerNivelPara(string codigoMateria)
{
	InformacionMateriaSegunCarrera* informacionMateriaSegunCarrera = this->contexto->BuscarInformacionMateriaSegunCarrera(codigoMateria);
	if(informacionMateriaSegunCarrera == NULL)
	{
		return;//Esto ocurre cuando se busca una materia que no figura entre las optativas ni las obligatorias.
	}
	list<string> codigosCorrelativas = informacionMateriaSegunCarrera->GetCodigoCorrelativas();
	list<string>::iterator itCorrelativas;
	for(itCorrelativas = codigosCorrelativas.begin(); itCorrelativas != codigosCorrelativas.end(); itCorrelativas++)
	{
		string codigoCorrelativa = *itCorrelativas;
		this->matrizAdyacencia->RegistrarCorrelativa(codigoMateria, codigoCorrelativa);
	}
};

void PriorizadorMaterias::ArmarArbolDeCorrelatividadesCompletoPara(string codigoMateria)
{
	list<InformacionMateria*> colaCorrelativas;
	InformacionMateria* materiaBase = this->contexto->BuscarInformacionMateria(codigoMateria);
	InformacionMateriaSegunCarrera* informacionMateriaSegunCarrera = this->contexto->BuscarInformacionMateriaSegunCarrera(codigoMateria);
	if(informacionMateriaSegunCarrera == NULL)
	{
		return;//Esto ocurre cuando se busca una materia que no figura entre las optativas ni las obligatorias.
	}
	colaCorrelativas.push_back(materiaBase);	
	do
	{
		InformacionMateria* proximaMateria = *(colaCorrelativas.begin());
		list<string> codigosCorrelativas = this->contexto->BuscarInformacionMateriaSegunCarrera(proximaMateria->GetCodigo())->GetCodigoCorrelativas();
		list<string>::iterator itKeys;
		for(itKeys = codigosCorrelativas.begin(); itKeys != codigosCorrelativas.end(); itKeys++)
		{
			string key = *itKeys;
			this->matrizAdyacencia->RegistrarCorrelativa(materiaBase->GetCodigo(), key);
			colaCorrelativas.push_back(this->contexto->BuscarInformacionMateria(key));
		}
		colaCorrelativas.remove(proximaMateria);
	} while(!colaCorrelativas.empty());
};